INTERFACING A .DLL or .EXE WITH POWERTRACKS This document applies to both .DLL and .EXE support, even though there are minor differences in behavior of .EXEs vs. DLLs. These differences, along with information about .EXE support, will be discussed later in this document. NOTE: Starting with PowerTracks Version 8.0, only 32-bit .DLLs and .EXEs can link to PowerTracks. Any 16-bit .DLL or .EXE programs need to be recompiled as 32-bit. Also, 32-bit .DLLs and .EXEs will not work with earlier version of PowerTracks. We suggest you focus only on creating 32-bit .EXEs since future versions of PowerTracks will be 32-bit only. NOTE: Since a 32-bit .EXE is NOT allowed to pass a pointer directly to another 32-bit .EXE, it is now required that you use a Memory Mapped File each time the .EXE passes a structure or string to PowerTracks. While this is inconvenient, it is not that complicated, and the EXEDEMO.DPR contains sample source code that makes it clear how to deal with Memory Mapped Files. The EXEDEMO.ZIP file containing the EXEDEMO project, contains a MEMMAP.PAS which can be used to easily create Memory Mapped Files as needed. For EXE programs: the rule is that you can NEVER pass anything to PowerTracks as a pointer, so you have to first create a Memory Mapped File for the structure you wish to pass. These Memory Mapped Files are NOT actual files on disk, but, when created, the Memory Mapped Files are given names that are used to identify them, and you must name them correctly so PowerTracks will recognize them. If You're using an .EXE, you would create memory mapped files within your .EXE using the exact file names discussed later in this document. For any message that formerly required a pointer, you would pass zero (Nil), since PTW will be use an API call to open for the memory mapped file name that is specific to the message you're sending to PTW. NOTE REGARDING DLLS: If you are interfacing a .DLL with PowerTracks, you do not need to use Memory Mapped Files. You can pass structures directly as pointers in the LParam parameter of a SendMessage, and PTW will use those pointers instead of attempting to open a memory mapped file. You could use Memory Mapped Files if you wanted to with a .DLL but, it would probably be easier to just pass pointers directly to the .EXE. For example, if you wish to pass the TExeInfo structure, you create a Memory Mapped File called 'PTWExeInfo', and this file is equal in size to the TExeInfoStructure. Each structure that gets passed to PTW, will have a corresponding name that must be used when creating the Memory Mapped File for the structure. Here are a list of the structures and the corresponding names: (unless otherwise noted, the file sizes must be set to the sizes of the structures) TExeInfo --> 'PTWExeInfo' is the name used for the Memory Mapped File TTrackInfo --> 'PTWTrackInfo' is the name used for the Memory Mapped File TIndexedMIDIData ---> 'PTWIndexedMIDIData' is the name used for the Memory Mapped File PChar ----> 'PTWString' is the name used for the Memory Mapped File in order to pass a PChar string (such as a file name, etc.) to PowerTracks. This file should be always be 257 bytes in size, regardless of how small a string you intend to pass to PTW. For example, when retrieving information about a track in PowerTracks, you must first create this Memory Mapped File: --------------------------------------------------------------- Uses MemMap; Var TrackMemMap:TMemMap; TrackInfo:PTrackInfo; TrackMemMap := TMemMap.Create('PTWTrackInfo',SizeOf(TTrackInfo)); If TrackMemMap = Nil then exit; TrackInfo := PTrackInfo(TrackMemMap.GetMemPtr); SendMessage(WinHandle,wm_MD_SetTrackNumber,SpinEdit1.Value,0); SendMessage(WinHandle,wm_MD_GetTrackInfo,0,0); -------------------------------------------------------------- In the Above code, the Memory Mapped File called 'PTWTrackInfo' is created with a size equal to the size of the TTrackInfoStructure. The file must be named exactly as 'PTWTrackInfo' because PowerTracks will look for that file when the wm_MD_GetTrackInfo or wm_MD_SetTrackInfo commands are received by PowerTracks. If you are using Memory Mapped Files, you must ALWAYS set the lparam field to zero. NOTE: The structures have changed in that they no longer contain any embedded pointers. For example, a structure that contained a PChar will now contain an array [0..128] of char. A structure containing a pointer to an array will now include the actual array. You can use the language of your choice (C++, Pascal, Delphi etc.) Once created, the .DLL (or .EXE) can be used by PowerTracks, and will appear to the user as a button on the Mixer Screen. Inside the .DLL (or .EXE), you will have easy access to the MIDI data that PowerTracks is receiving and sending out, and will also easily be able to send out your own MIDI data to your synthesizer. Examples of possible .DLLs (or .EXEs) that could be created are: - 'front panel' type functionality for a specific synthesizer. - editor/ librarian for a synthesizer. - utility program - MIDI monitor - displaying MIDI data in a custom format or in a graphical way. - using MIDI data to trigger graphics etc. *************************************************************** NOTE: This documentation covers the Programming of .DLLs using PowerTracks. This is nothing to do with the international language support .DLLs you can make for other language support like French, Spanish etc. If you are interested in making an international version of PowerTracks (or another PG Music program), you'll need different documentation, please contact us for this. **************************************************************** When you create the .DLL (or .EXE), you name it starting with a $ sign, and put it in the PowerTracks directory c:\pt. When the user selects a .DLL (or .EXE), the .DLL and .EXE files with a $ sign will appear in the list, and he can choose your .DLL or .EXE. In the case of a .DLL, once your DLL is chosen, the DLL is run and you are passed a structure that contains information like: - the Handle of the MIDI Output device that PowerTracks is set to use. (Interfacing with an .EXE involves sending the wm_MD_EXESignIn to obtain the same structure that is passed to .DLLs, and will be discussed later in this document.) You can use the output handle immediately inside your .DLL by calling the MIDIOutShortMsg routine with the handle, and the MIDIData that you want to send out. If your application is only sending MIDI out (and not processing input), then this Handle is virtually the only piece of information that you need. ************IMPORTANT INFO REGARDING EXE PLUGINS*************** It appears that WinXP doesn't support the sharing of MIDI output ports between two different applications, so we created a WM_MD_SendShortMsg that lets your .EXE plugin send a MIDI short message via PowerTracks without your plugin needing to open it's own MIDI Output port. DLL MIDI Plugins can still call MidiOutSHortMsg directly. **************************************************************** - a circular buffer prepared by PowerTracks with all the incoming MIDI data that is coming from MIDI thru (that the user is playing) as well as the outgoing data that PowerTracks is sending. This buffer includes regular MIDI data, as well as Sys-EX events. If your application is processing the data in this buffer (for a MIDI monitor for example), then it will be regularly reading this buffer. You can use any language that is capable of compiling to a .DLL or .EXE. This includes C,C++, Pascal and Delphi. The advantages of creating a .DLL (or .EXE) to use in PowerTracks are: - The .DLL or .EXE is easily accessible to the user as it appears as a button on the Mixer Window, and via a menu item starting with PTW 3.0b. - the .DLL or .EXE uses the same output handle, and input buffer as PowerTracks, overcoming the limit of '1 application per driver' that many applications have, - simplifies Windows MIDI programming. You don't need to worry about finding the output handle to use, or worry about collecting the incoming data in a buffer. This is done for you. - re-usability. Other PG Music programs (Band-in-a-Box, The Pianist may soon support these .DLLs and .EXEs, so that when you create a .DLL or .EXE for PowerTracks, it will also work for these other programs, (NOTE: this is assuming that the .DLL/.EXE doesn't do things that are unsupported by the other programs. For example, since the Pianist is not a sequencer it may not support all the new editing messages that PowerTracks does.) Questions regarding the documentation or DLL/EXE programming should be addressed to support@pgmusic.com ************************************************* The following documentation is in Pascal. If using C, you'd need to convert this Procedure to Pascal. We include a complete sample application called GS Reset, which compiles to a .DLL. This simple .DLL has a button that resets a GS synthesizer, and will give you a simple introduction to the .DLL programming. This GSRESET code is found in the file GSRESET.ZIP. The GS RESET code is in 'Delphi' , which is the newest implementation of Pascal for Windows from Borland . We also include a demo exe in EXEDEMO.ZIP, which is a demo .EXE written in Delphi with complete source code. A .DLL must have the following procedure, which is called by PowerTracks: Procedure LaunchTheDialog(HWindow:Hwnd;TheCurrentPart:Integer;PortHandle:THandle; TheMIDIInfo:PMIDIInfo;ProgNum,Language:Byte); Export; You should make sure that the LaunchTheDialog procedure exits gracefully if is called twice before the first call to the dialog finished executing. If you don't do this then there could be problems if we added .DLL support to other programs and two programs attempted to use the same .DLL at the same exact time. Also, the .DLL should still remain in memory even if the user closes the dialog, because PowerTracks will assume the .DLL is still active and could call the LaunchTheDialog procedure again if the user presses the button. Note: A dialog can show a normal window instead of a dialog when the LauchTheDialog procedure is called. This would let the user switch back and forth between the window and PowerTracks while the .DLL is loaded. However, your .DLL should be written in such a way that it exits the LaunchTheDialog procedure if called while the window is already currently displayed, rather than displaying duplicate windows! The HWindow is a handle to the mixer window of PowerTracks. This may be needed if your programming language requires a parent window to launch a dialog from within a .DLL, or when the .DLL sends a message to the mixer window such as WM_BufferNotNeeded (explained below). TheCurrentPart is the current part number or channel number of a 16 part synth. You can ignore this if the .DLL you're writing isn't for a specific synth. The PortHandle is a handle to a MIDIOutput port in PowerTracks. It is the output port of the current track. You can use this handle when calling multimedia API functions such as midiOutShortMsg. TheMIDIInfo is pointer with a type of PMIDIInfo, which is a pointer to a TMIDIInfo data structure. The Definition of PMIDIInfo is as follows: PMIDIInfo = ^TMIDIInfo; TMIDIInfo = Record TheMIDIEventArray:PMIDIEventArray {Pointer to a circular buffer array}; MIDIEventHead,MIDIEventTail:Word; {Head and Tail of buffer} SysExArray:PSysExArray; {Pointer to the array of Sysex data} End; The MIDIEventArray, and SysExArray are two items that are used if a .DLL needs to receive output message from PowerTracks. These items can be ignored by a .DLL or .EXE that doesn't need them. If a program doesn't need to use these items it should send a special message to the handle of the window that was passed in the HWindow parameter of LaunchTheDialog. This message is as follows: Const wm_BufferNotNeeded = wm_User + 33; e.g SendMessage(HWindow,wm_user+33,0,0); This tells PowerTracks a .DLL or .EXE won't be using the buffers so it doesn't have to waste time filling them. Keep in mind that using these buffers requires that you install a timer to read them often, such as a WM_TIMER, which may not be adequate, or preferably a multimedia timer, which is much more accurate. Reading and processing these buffers in a .DLL or .EXE could possibly take significant time away from PowerTracks to be able to do things like redraw screens quickly, etc. so this feature may be only desirable on fast 486 or higher machines. The program will keep adding to the buffers in a circular fashion, so it's the responsibility of the .DLL or .EXE to read the data quickly enough not to miss any data. PMIDIEventArray = ^TMIDIEventArray; TMIDIEventArray = Array [1..1000] of TMIDIEvent TMIDIEventArray is a circular buffer of TMIDIEvents. A TMIDIEvent is defined as follows: TMidiEvent = Record Source:Word; {0 for thru; 1 for output} Event:Longint; {MIDI Event} End; The source indicates whether the event was a normal output event or a thru event. The Event field is a long integer storing the MIDI data bytes. The most significant byte contains the status, and the 2nd and 3rd most significant bytes contain the data bytes, and the least significant byte isn't used. This is the same structure that is used by multimedia windows for MIDIOutShortMsg. The PSysExArray is a pointer to a TSysexArray data structure as shown below: PSysExArray = ^TSysExArray; TSysexArray = Array[0..64000] of Byte; PowerTracks will fill the SysexArray field with bytes of SysexData and then fill the TheMIDIEventArray buffer with two special $F0/$F7 events that indicate that indicate the position of the beginning and end of a sysex message. For example: Source Event Interpretation 0 $903C4000 ($90 $3C $40) Note on Middle C, the source of 0 means that MIDI thru (i.e. input) was the source of the message. 1 $99244000 ($99 $24 $40) A Drum note was sent out the MIDI output from PowerTracks (assuming drums are on channel 10) (The Source=1 indicates that PTW sent the note out.) 0 $F0000000 ($F0 $00 $00) A SysEx message was received by PTW from MIDI. Sysex messages starts at offset $0000 0 $F7010400 ($F7 $01 $04) The SysEx message ends at offset $0104 indicating that the message stored in the sysex is from 0 to $104, so it is 261 bytes long. 1 $C1200000 ($C1 $20) A patch change of 33 was sent out by the program. (assuming you consider patch numbers to begin with 1 and end with 128) 0 $F0010500 ($F0 $01 $05) Another sysex has been stored. 0 $F7010900 ($F7 $01 $09) This one ends soon so it is only 5 bytes long. The ProgNum parameter in the LuanchTheDialog procedure tells which PG Music program called the .DLL. Currently only PowerTracks interfaces with this type of DLL, but this feature could be added to the other programs as well. Here are the various possible values for the ProgNum parameter: 0 = Unspecified 1 = PowerTracks (the only program currently interfacing with these .DLLs or .EXEs) 2 = Band-in-a-Box 3 = Pianist (Classical, New Orleans, or ragtime) 4 = JazzPianist 5 = Guitarist 6 = SC-PRO A .DLL can be loaded, or an .EXE can be launched, when the user presses the DLL button in the PowerTracks Mixer window. All DLLs or EXEs in the same directory as PTW.EXE that begin with a dollar sign character, e.g. $SC.DLL will appear in a dialog that lets the user choose a .DLL or an .EXE. Once a DLL is selected, the LaunchTheDialog Procedure will be called by PowerTracks when the user presses the button next to the DLL button. This button will be named 'GS' in the case of $GS.DLL. The .DLL will remain loaded in memory until either PTW is finished running, or the user selects a different .DLL. (Interfacing with an .EXE involves sending the wm_MD_EXESignIn and wm_MD_EXESignOut messages which are discussed later in this document.) Additional Messages: Starting with PTW 3.0b, a new set of messages has been added to expand the capabilities of a .DLL, plus the ability to interface with .EXEs was also added to PTW 3.0b. Since many of these messages are appropriate for PowerTracks, only some of them may possibly be supported by other programs. Below are the additional messages, their numeric values will be listed at the end of this document. Each message is listed here by name. On the same line as the message name, we'll show show the usage of each parameter (wParam, lParam, and result), plus a description of the message. MESSAGE wParam lParam Returns wm_MD_GetVersion not used not used version (current version is '1'. If version returned is less than 1, then it can be assumed that these messages are not supported, and interfacing with .EXEs isn't supported.) wm_MD_SetTrackNumber wTrackNum not used Track Number (This sets the track number which will be used when track-related messages are sent such as wm_MD_InsertTrackEvent, etc. You first set the track number, and then you can use messages to edit the track. The wTrackNum can be a number ranging from 1 to the highest track which is returned from the wm_MD_GetHighestTrack message) wm_MD_GetTrackNumber not used not used Track Number (This returns the track number set with the wm_MD_SetTrackNumber message) wm_MD_GetTrackNumberOfEvents not used not used result (This returns the number of events in a track) wm_MD_GetHighestTrack not used not used PTW returns 48 (This returns the highest track number supported by the program. PTW returns 48, since it has 48 tracks) wm_MD_DeleteTrackEvent not used dwIndex result (This deletes an event from a track. Returns 1 for success, 0 for failure) wm_MD_UpdateScreens not used not used result (This message updates the screens in the program. You should send this message any time you want PTW to update its screens. For example, if you've just did an editing routine, you should send this message so that PTW's screens will reflect the changes you've made.) wm_MD_InsertTrackEvent not used PIndexedMidiData result (This will insert an event into a track. The Lparam is a pointer to a TIndexedMidiData structure which is as follows: TIndexedMIDIData = Record Index:Longint; (zero-based index of the event, 1st event has index of zero) MIDIData:Longint; (This is the same kind of longint used for MIDI data as Windows 3.1 in functions such as MIDIOutShortMsg. The least significant byte is the status, and the 2nd and 3rd least significant bytes are used for data bytes 1 and 2. The most significant byte is not used. For example a Middle C on channel 1 with a velocity of 100 ($90 $3C $64) would be $00643C90. Keep in mind that PowerTracks stores notes as one event with a duration rather than two separate note on/off events) Time:Longint; (This is a time in ticks where 0 is the song start) Duration:Word; (this is used for the duration if the event is a note) LyricText: PChar; (this is a PChar (pointer to a null terminated string), and this field is used if the event is a Lyric event $0000007F. Setting the MIDI data to $0000007F tells PTW that the event is a lyric rather than a MIDI event. dw1:Longint; (not used) dw2:Longint; (not used) End; Note: the pointer send in this message must be a valid pointer. You can use the '@' operator in front of a TIndexedMidiData variable. For example, if you've got a variable called MyIndexedData that is a TIndexedMidiData, the LParam field could be Longint(@MyIndexedData). Typecasting to a longint is necessary since the Lparam field requires a longint. wm_MD_ModifyTrackEvent not used PIndexedMidiData result (this is sent to modify an event of a track. If you change the time, the event will be moved to a different location in the track according to the time. All fields in the PIndexedMidiData must be set to the correct values for the event even if you're only changing one field for the event.) wm_MD_GetTrackEvent not used PIndexedMidiData result (this gets an event from a track and fills the PIndexedMidiData with the information about the event) wm_MD_GetTrackInfo not used PTrackInfo result (This is used to set track information such as the track name, channel, etc. Msg.LParam is a pointer to a TTrackInfo structure which is as follows: TTrackInfo = Record PlayMuteFrozenStatus:Byte; {0 = Frozen, 1 = Muted, 2 = Play) Name:PChar; (PChar with the name of the Track. You MUST make sure this is a valid pointer with enough space allocated for PowerTracks to fill with a track name) Channel:Byte; (Forced channel) Key:ShortInt; (key transpose) Vel:ShortInt; (forced vel +/-) Port:Byte; (port number) Patch:ShortInt; (prg number. -1 thru 127 -- this is always zero-based with a value of -1 meaning no patch) Bank:ShortInt; (bank number. -1 thru 127) Loop:Word; (loop. 0 thru 999) Dw1:Longint; (unused) Dw2:Longint; (unused) w1:Word; (unused) i1:Integer; (unused) End; wm_MD_SetTrackInfo not used PTrackInfo result (This sets the track info with the information you've placed into a TTrackInfo structure. LParam is a Pointer to a TTrackInfo structure. All fields must be set even if you're only changing one field.) wm_MD_GetSongTime not used not used Song Time in ticks (gets current song time in ticks) wm_MD_SetSongTime not used dwSongTime result (sets the song time in ticks) wm_MD_Play not used not used result (starts playback. Returns 1 for success, 0 for failure. Failure results if playback is already happening) wm_MD_Stop not used not used result (stops playback. Returns 1 for success, 0 for failure) wm_MD_GetFromValue not used not used FromValue (returns from value in ticks) wm_MD_GetThruValue not used not used ThruValue (returns thru value in ticks) wm_MD_SetFromValue not used dwFromValue Result (Sets from value in ticks, Returns 1 for success, 0 for failure) wm_MD_SetThruValue not used dwThruValue Result (Sets thru value in ticks, Returns 1 for success, 0 for failure) wm_MD_IsTrackHighlighted wTrackNum not used Result (Used to tell if a particular track is highlighted. This uses Wparam for the track number) wm_MD_GetSongPPQ not used not used SongPPQ (Returns PPQ of the song) wm_MD_GetNumberofMeterMapEvents not used not used dwMeterMapEvents (Returns number of events in Meter Map) wm_MD_GetMeterMapNumerator not used dwIndex dwNumerator (Returns Numerator of meter map event, or zero for failure) wm_MD_GetMeterMapDenominator not used dwIndex dwDenominator (Returns Denominator of meter map event, or a value <= 0 indicates failure) wm_MD_GetMeterMapTime not used dwIndex dwTime (Returns Time in Ticks of meter map event, or -1 for failure) wm_MD_GetMeterMapMeasure not used dwIndex dwMeasure (Returns Measure of meter map event, or -1 for failure) wm_MD_SetMeterMapNumerator not used dwIndex result (Sets Numerator of Meter Map event. Returns 1 for success, 0 for failure) wm_MD_SetMeterMapDenominator not used dwIndex result (Sets Denominator of Meter Map event. Returns 1 for success, 0 for failure) wm_MD_InsertMeter wMeasure dwNumeratorDenominator result (Inserts meter map event at measure location in wMeasure (not an index). The high word of dwNumeratorDenominator is the numerator, and the low word is the denominator. Result is 1 for success, 0 for failure. Duplicate entries at same measure aren't inserted by this message) wm_MD_DeleteMeter not used dwIndex result (This deletes meter map event at dwIndex . If only 1 meter map event exists it won't get deleted. Returns 1 for success, 0 for failure) wm_MD_GetTempoMapTempoValue not used dwIndex dwTempoValue (returns Tempo value of tempo map event) wm_MD_GetTempoMapTime not used dwIndex dwTicks (returns time in ticks of tempo map event) wm_MD_SetTempoMapTempoValue wTempo dwIndex Result (returns 1 for success, 0 for failure) wm_MD_GetNumberofTempoMapEvents not used not used dwNumberEvents (returns number of Tempo Map events) wm_MD_InsertTempo wTempo dwTimeInTicks Result (returns 1 for success, 0 for failure. Will not insert multiple events at same time location) wm_MD_DeleteTempo not used dwIndex Result (returns 1 for success, 0 for failure. Will not delete event if it's the only tempo map event) wm_MD_GetSongKeySignature not used not used dwKeySigValue (returns value representing key signature of song ranging form -7 to 7. The key of C = 0. Negative numbers represent flats (e.g. -1 = f, since it has 1 flat, -7 = Cb). Numbers above zero represent sharps (e.g. 1 = G, since the key of G has 1 sharp) wm_MD_SaveUndoTrackData not used PChar result (this caused PowerTracks to save the data of all the track so subsequent editing can later be 'undone'. The PChar should be the text that will appear in the PTW Undo menu item after the word, 'Undo'. e.g. '(Patch Strip)'. Keep it short in length. Returns 1 for success, 0 for failure) wm_MD_Undo not used not used result (This will restore the track data saved with wm_MD_SaveUndoTrackData, if any data was saved. The user can also use the PTW undo so you don't need to provide your own undo if you've send the message to save the undo data.) wm_MD_ExeSignIn not used PExeInfo result (This is sent by an .EXE application to 'sign in' to PowerTracks. This message is number wm_user_258 for the 32-bit version of PowerTracks. Note: It used to be wm_user+240 for the 16-bit version. Note: Your application first has to find the main window handle to PowerTracks, but if you're a Delphi programmer, and you use our PGMusicLink component, this is done virtually automatically. If you're using another language such as C++, you could look at the source code (PGLINK.PAS) and it wouldn't be too difficult to see how our component is able to find PTW's main window handle, since Delphi uses the same Windows API calls that other languages use. An .EXE uses this message to retrieve the same information that is retrieved when PTW calls the LaunchTheDialog procedure in a .DLL. The PExeInfo is a pointer to a TExeInfo structure, which is: TEXEInfo = Record HWindow:HWnd; (handle to main window of PowerTracks) TheCurrentPart:Integer; (current part number. Actually channel number of current track) PortHandle:THandle; (handle to output port number 1 of PowerTracks) TheMIDIInfo:PMIDIInfo; (Pointer to TMIDIINFO structure, as described earlier in this document. This must be a valid pointer. Make sure you don't forget to initialize it.) ProgNum, (ProgNum, as described earlier in this document) Language:Byte; (don't worry about this unless you're planning to support foreign languages. This number just indicates what language PowerTracks is being used for displaying text. 0 = English, 3 = Chinese, 6 = French, 7 = German, 8 = Finnish, 9 = Italian, 10=Japanese, 19=Spanish) End; Note: the pointer sent in this message must be a valid pointer. You can used the '@' operator in front of a TExeInfo variable. For example, if you've got a variable called MyExeInfo that is a TExeInfo, the LParam field could be Longint(@MyExeInfo). Typecasting to a longint is necessary since the Lparam field requires a longint. If the Sign In is successful, this message will return 1. If another .EXE is already signed in, or a .DLL is active it will return 0. Your .EXE should be named beginning with the '$' character, e.g. '$MYEXE.EXE', so that it can be launched from within PTW. wm_MD_ExeSignOut not used not used result (this causes the currently signed in .EXE to be signed out of PowerTracks. Returns 1 for success, 0 for failure. Do not send this message unless the program is currently successfully signed into PTW.) wm_MD_SaveFile not used PCharName result (This will cause PTW to save the current song to the file named in PCharName. PTW's file name will then be set to that name. PCharName must be a valid PChar) wm_MD_LoadFile not used PCharName result (This will cause PTW to load the file named in PCharName. PCharName must be a valid PChar) wm_MD_GetCurrentFileName not used PCharName result (Returns PTW's current file name by filling PCharName. PCharName must be a valid PChar with at least 80 characters allocated to it) wm_MD_GetCurrentTrack not used not used dwTrackNumber (Returns number of the currently selected track in the Tracks Window) wm_MD_IsPlayBackHappening not used not used result (returns 1 if playback is happening, or 0 if playback isn't happening) wm_MD_GetOutputPortHandle wPortNum not used dwPortHandle (This can be used to obtain the output port handle of ports 1 through 16 in PowerTracks. We added this because only the handle to port 1 is obtained during initialization. wPortNum can be a number from 1 through 16. If you attempt to retrieve the handle of a port that is greater than the max available, but within the 1- 16 range, then the handle returned will be the handle to the highest available port. For example, if only one output port is available, a wPortNum value of 2 will give you the handle to Port 1. You can use the wm_MD_GetNumberOfOutputPorts to return the number of currently available output ports in PTW.) wm_MD_GetNumberOfOutputPorts not used not used dwNumberOfPorts (this returns the number of currently available output ports in PTW, or 0 if no ports are available) wm_MD_IsPowerTracks not used not used not used (This returns 259. The PG Music Link component will send this message to a window to determine if PowerTracks instead of another application such as the PowerTracks .HLP file. If 259 is returned in Msg.Result, then the window is assumed to be the main window of PowerTracks. If 259 isn't returned then the window is assumed to be another program such as the .HLP file.) wm _MD_SendShortMsg wPortNum LDataArray (This will will let you send MIDI data via PowerTracks in the form of a short MIDI output message. WParam should be set to a port number (1 to 16) and LParam should be a LongInteger which contains the MIDI data in the same 4-byte format as required by MidiOutShortMsg. The reason this message is implemented is because WindowsXP won't let an .EXE MIDI plugin directly send a MIDI output message using the porthandles that were opened in PowerTracks. In other words XP doesn't let apps share the same port handle, so we created this message that lets you send a MIDI message by routing it through PowerTracks.) DIFFERENCES BETWEEN INTERFACING .EXES AND .DLLS TO POWERTRACKS Starting with PTW 3.0b, .EXEs can now be interfaced to PowerTracks. EXEs are stand-alone applications as opposed to DLLs which are libraries that are loaded by EXE applications. Advantages of using .DLLs as opposed to EXEs: 1) A .DLL can have a dialog that will behave as if it were built-in to PTW. This true if you create a .DLL that has a modal dialog (one that doesn't let you switch to another window in the program unless you hit OK) An example of this is our $GS.DLL. When the GS dialog pops up, you can't switch to another window in PowerTracks, so it won't get obscured. NOTE: On the other hand, you may want to allow the user to be able to switch back and forth between the window of your program so this is only really an advantage if you want a modal dialog. 2) DLLs remain in memory until unloaded by PowerTracks so you can create an editing dialog, such as the $GS.DLL, that stores the current settings in memory after the dialog has been closed during the current session and will re-display them the next time the dialog is popped-up during the current PTW session. 3) You can have a high resolution multimedia timer interrupt in a .DLL. You could have an .EXE that makes use of an MM timer interrupt but the .EXE itself would then have use a .DLL for all the MM timer interrupt callback routines. (You can, of course, have ordinary (non-multimedia) low resolution windows timer routines in an .EXE.) 4) You can call MidiOutShortMsg and MidiOutLongMsg directly with the same port handles that are used by PowerTracks. (Note: We created a WM_MD_SendShortMsg that can be used to send a short message via PTW. THis works for both DLLs and EXEs) Advantages to using an .EXE as opposed to a .DLL: 1) An .EXE is easier to debug than a .DLL. In fact, Delphi itself can't debug a .DLL. You would have to purchase the latest version of Turbo Debugger for Windows. On the other hand, you could first make your program an .EXE, and then, when you've got it debugged, you could make it into a .DLL, assuming it doesn't use any multimedia timer (MMSYSTEM) routines. 2) An .EXE could be written in such a way that, instead of being launched by PTW, it could be run by itself, and will find PTW (or launch PTW if necessary). While this launching feature is a nice feature, it is more important that an .EXE be written so that it can be launched by Powertracks rather than the other way around. 3) The PGMusicLink Component. Our demo .EXE program, EXEDEMO.DPR, is a Delphi Project that contains a component called PGMusicLink, and is contained in PGLINK.PAS. The component makes it very easy for an .EXE to link to PowerTracks. You can use it for your .EXE applications. You don't have to use it, but, if you're using Delphi, then using this component makes creating your application easier. Keep in mind that even if you've launched an .EXE from within PowerTracks the .EXE still has to locate PTW.EXE's main window handle and the PGMusicLink component takes care of this for you. USING THE PGMUSICLINK COMPONENT: The following will explain how you can use the PGMusicLink component in your applications. We've included a demo .EXE program written in Delphi, called EXEDEMO.DPR. All the source code is included, so you can study it in addition to this documentation. To use the component, you first load it into the Delphi component library using the Options | Install Components command. This will bring up a dialog that will let you add PGLINK.PAS to the component library. After you've installed the component, Delphi will recompile the component library, and then it will appear in the component palette in the 'Samples' page. You can then click on the component and drag it to the main form of the application. Your application can launch PTW simply by referencing the component's MainWinHandle property. The component takes care of issues such as finding PTW if it's already running, launching it if necessary, and prompting the user for the path name if necessary. If this property is equal to zero, then that means the component could not link to PTW. The component issues error messages to the user and gives the user a chance to correct errors such as an incorrect path name. Since the component does all this work, if it should turn out that this property is equal to zero (e.g. if your window's PGMusicLink component is called PGMusicLink1, and PGMusicLink.MainWinHandle = 0) your application can assume the component couldn't link and the user has already been informed of this, so your program could simply issue one final message such as 'Could Not Link To PowerTracks, quitting...' and then simply stop executing as our EXEDEMO.DPR application does. You can give the user a chance to link to a different program after initialization. For example, if we eventually add linking support to other programs such as Band-in-a-Box, then having a 'Choose .EXE' button on your main window could let the .EXE be used with other programs. There is a component method called PromptUserForExeName which brings up a dialog prompting the user to choose a different .EXE to link to, and returns true if the user selected a different .EXE name. If the user has chosen a different .EXE, then the component signs out of the currently linked .EXE. Your application then just has to reference the MainWinHandle property again to obtain the handle to the new .EXE, and if the handle is equal to 0 then that means linking to the different .EXE failed (and the component has already issues error message and given the user a chance to enter a different path name, etc). If the user is ever prompted for a different .EXE name and presses OK, the path of that .EXE will be stored in a file called PGLINK.INI which resides in the directory of your application. This file will be read by the component the next time your application is run. If we add linking support to other programs besides PTW, and your application were meant for use with another program, such as BBW, you can change the default name of the .EXE that the component links to by editing the ExeName property at design time. By default, the .EXE name is set to 'PTW.EXE'. You could set it to, say, 'BBW.EXE' if we added linking support to BBW and your .EXE were designed to link to BBW rather than PowerTracks. In summary, the PGMusicLink component has two properties and one method function that you need to be aware of: 1) The MainWinHandle property which, when referenced by your application (e.g TheHandle := PGMusicLink1.MainWinHandle) will either obtain the handle to PTW or will return 0 if the component couldn't link. 2) The ExeName property, which can be changed at design time. 3) The PromptUserForExeName Function that you can use to give the user a chance to link to a different .EXE after initial linking was successful. Here's a list of all the messages with their numeric values: Const wm_MD_BufferNotNeeded = wm_User + 33; Const wm_MD_GetVersion = wm_User + 200; Const wm_MD_SetTrackNumber = wm_User + 201; Const wm_MD_GetTrackNumber = wm_User + 202; Const wm_MD_GetTrackNumberOfEvents = wm_User + 203; Const wm_MD_GetHighestTrack = wm_User + 204; Const wm_MD_DeleteTrackEvent = wm_User + 205; Const wm_MD_UpdateScreens = wm_User + 206; Const wm_MD_InsertTrackEvent = wm_User + 207; Const wm_MD_ModifyTrackEvent = wm_User + 208; Const wm_MD_GetTrackEvent = wm_User + 209; Const wm_MD_GetTrackInfo = wm_User + 210; Const wm_MD_SetTrackInfo = wm_User + 211; Const wm_MD_GetSongTime = wm_User + 212; Const wm_MD_SetSongTime = wm_User + 213; Const wm_MD_Play = wm_User + 214; Const wm_MD_Stop = wm_User + 215; Const wm_MD_GetFromValue = wm_User + 216; Const wm_MD_GetThruValue = wm_User + 217; Const wm_MD_SetFromValue = wm_User + 218; Const wm_MD_SetThruValue = wm_User + 219; Const wm_MD_IsTrackHighlighted = wm_User + 220; Const wm_MD_GetSongPPQ = wm_User + 221; Const wm_MD_GetNumberofMeterMapEvents = wm_User + 222; Const wm_MD_GetMeterMapNumerator = wm_User + 223; Const wm_MD_GetMeterMapDenominator = wm_User + 224; Const wm_MD_GetMeterMapTime = wm_User + 225; Const wm_MD_GetMeterMapMeasure = wm_User + 226; Const wm_MD_SetMeterMapNumerator = wm_User + 227; Const wm_MD_SetMeterMapDenominator = wm_User + 228; Const wm_MD_InsertMeter = wm_User + 229; Const wm_MD_DeleteMeter = wm_User + 230; Const wm_MD_GetTempoMapTempoValue = wm_User + 231; Const wm_MD_GetTempoMapTime = wm_User + 232; Const wm_MD_SetTempoMapTempoValue = wm_User + 233; Const wm_MD_GetNumberofTempoMapEvents = wm_User + 234; Const wm_MD_InsertTempo = wm_User + 235; Const wm_MD_DeleteTempo = wm_User + 236; Const wm_MD_GetSongKeySignature = wm_User + 237; Const wm_MD_SaveUndoTrackData = wm_User + 238; Const wm_MD_Undo = wm_User + 239; Const wm_MD_ExeSignIn = wm_User + 258; Const wm_MD_ExeSignOut = wm_User + 241; Const wm_MD_SaveFile = wm_User + 242; Const wm_MD_LoadFile = wm_User + 243; Const wm_MD_GetCurrentFileName = wm_User + 244; Const wm_MD_GetCurrentTrack = wm_User + 245; Const wm_MD_IsPlayBackHappening = wm_User + 246; Const wm_MD_GetOutputPortHandle = wm_User + 247; Const wm_MD_GetNumberOfOutputPorts = wm_User + 248; Const wm_MD_ExeSignIn = wm_User + 258; Const wm_MD_IsPowerTracks = wm_user + 259; Const wm_MD_SendShortMsg = wm_user + 260 ----------------------End of Document - PTWDLL.TXT--------------